﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using TouchSocket.Core;
using TouchSocket.Http;
using TouchSocket.Http.WebSockets;
using TouchSocket.Rpc;
using TouchSocket.Sockets;
using TouchSocket.WebApi;

namespace TouchSocketDemo.Core
{
    public class WebSockSvr
    {
        public List<IHttpSession> ClinetList { get; set; } = new List<IHttpSession>();
        private HttpService service;
        public WebSockSvr() 
        {
            service = new HttpService();
        }
        public async Task Start() 
        {
            await service.SetupAsync(new TouchSocketConfig()//加载配置
                 .SetListenIPHosts(4040)
                 .ConfigureContainer(a =>
                 {
                     //a.AddConsoleLogger();
                 })
                 .ConfigurePlugins(a =>
                 {
                     a.UseWebSocket().SetWSUrl(null).UseAutoPong();
                     //a.Add<MyWebSocketPlugin>();
                     a.Add(typeof(IWebSocketHandshakedPlugin), async (IWebSocket client, HttpContextEventArgs e) =>
                     {
                         ClinetList.Add(client.Client);
                         await e.InvokeNext();
                     });
                     a.Add(typeof(IWebSocketClosingPlugin), async (IWebSocket client, ClosedEventArgs e) =>
                     {
                         ClinetList.Remove(client.Client);
                         await e.InvokeNext();
                     });

                     a.Add(typeof(IWebSocketReceivedPlugin), async (IWebSocket client, WSDataFrameEventArgs e) =>
                     {
                         switch (e.DataFrame.Opcode)
                         {
                             case WSDataType.Close:
                                 {
                                     //this.m_logger.Info("远程请求断开");
                                     await client.CloseAsync("断开");
                                 }
                                 return;

                             case WSDataType.Ping:
                                 await client.PongAsync();//收到ping时，一般需要响应pong
                                 break;

                             case WSDataType.Pong:
                                 break;

                             default:
                                 break;
                         }

                         await e.InvokeNext();
                     });

                     a.UseWebSocketReconnection();
                     //a.Add(typeof(IWebSocketHandshakedPlugin), () =>
                     //{
                     //    Console.WriteLine("WebSocketHandshaked");
                     //});

                     //a.Add(typeof(IWebSocketClosingPlugin), () =>
                     //{
                     //    Console.WriteLine("WebSocketClosing");
                     //});

                     //a.Add(typeof(IWebSocketClosedPlugin), () =>
                     //{
                     //    Console.WriteLine("WebSocketClosed");
                     //});
                     //a.Add(typeof(IWebSocketReceivedPlugin), async (IHttpSession c, WSDataFrameEventArgs e) =>
                     //{
                     //    //Console.WriteLine("IHttpSessionClient");

                     //    await e.InvokeNext();
                     //});

                     //a.Add<MyWebSocketPlugin>();
                 }));
            await service.StartAsync();
        }


        public void SendDatas()
        {
            for (int i = 0; i < 200; i++)
            {
                Task.Run(async () =>
                {
                    while (true)
                    {
                        try
                        {
                            var clientList = ClinetList.ToList();
                            for (int j = 0; j < clientList.Count; j++)
                            {
                                var sock = (HttpSessionClient)clientList[j];
                                if (sock.Online)
                                {
                                    // sock.MainSocket.Send(Encoding.UTF8.GetBytes($"Dev[{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}, 12.34, 34.56, 56.78, \"77705683\"]"));
                                    await sock.WebSocket.SendAsync($"Dev[{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}, 12.34, 34.56, 56.78, \"77705683\"]");
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine("出现异常：" + ex.Message + "\r\n" + ex.StackTrace);
                        }
                        finally
                        {
                            await Task.Delay(10);
                        }
                    }
                });
            }

        }


        public class MyServer : RpcServer
        {
            private readonly ILog m_logger;

            public MyServer(ILog logger)
            {
                this.m_logger = logger;
            }

            [Router("/[api]/ws")]
            [Router("/[api]/[action]")]
            [WebApi(HttpMethodType.GET)]
            public async Task ConnectWS(IWebApiCallContext callContext)
            {
                if (callContext.Caller is HttpSessionClient socketClient)
                {
                    if (await socketClient.SwitchProtocolToWebSocketAsync(callContext.HttpContext))
                    {
                        this.m_logger.Info("WS通过WebApi连接");
                    }
                }
            }
        }

        public class MyWebSocketPlugin : PluginBase, IWebSocketHandshakingPlugin, IWebSocketHandshakedPlugin, IWebSocketReceivedPlugin
        {
            public MyWebSocketPlugin(ILog logger)
            {
                this.m_logger = logger;
            }

            public async Task OnWebSocketHandshaking(IWebSocket client, HttpContextEventArgs e)
            {
                if (client.Client is IHttpSessionClient socketClient)
                {
                    //服务端

                    var id = socketClient.Id;
                }
                else if (client.Client is IHttpClient httpClient)
                {
                    //客户端
                }
                this.m_logger.Info("WebSocket正在连接");
                await e.InvokeNext();
            }

            public async Task OnWebSocketHandshaked(IWebSocket client, HttpContextEventArgs e)
            {
                this.m_logger.Info("WebSocket成功连接");
                await e.InvokeNext();
            }

            private readonly ILog m_logger;

            public async Task OnWebSocketReceived(IWebSocket client, WSDataFrameEventArgs e)
            {
                switch (e.DataFrame.Opcode)
                {
                    case WSDataType.Close:
                        {
                            this.m_logger.Info("远程请求断开");
                            await client.CloseAsync("断开");
                        }
                        return;

                    case WSDataType.Ping:
                        this.m_logger.Info("Ping");
                        await client.PongAsync();//收到ping时，一般需要响应pong
                        break;

                    case WSDataType.Pong:
                        this.m_logger.Info("Pong");
                        break;

                    default:
                        {

                            //其他报文，需要考虑中继包的情况。所以需要手动合并 WSDataType.Cont类型的包。
                            //或者使用消息合并器

                            //获取消息组合器
                            var messageCombinator = client.GetMessageCombinator();

                            try
                            {
                                //尝试组合
                                if (messageCombinator.TryCombine(e.DataFrame, out var webSocketMessage))
                                {
                                    //组合成功，必须using释放模式
                                    using (webSocketMessage)
                                    {
                                        //合并后的消息
                                        var dataType = webSocketMessage.Opcode;

                                        //合并后的完整消息
                                        var data = webSocketMessage.PayloadData;

                                        if (dataType == WSDataType.Text)
                                        {
                                            //按文本处理
                                        }
                                        else if (dataType == WSDataType.Binary)
                                        {
                                            //按字节处理
                                        }
                                        else
                                        {
                                            //可能是其他自定义协议
                                        }
                                    }
                                }
                            }
                            catch (Exception ex)
                            {
                                this.m_logger.Exception(ex);
                                messageCombinator.Clear();//当组合发生异常时，应该清空组合器数据
                            }

                        }
                        break;
                }

                await e.InvokeNext();
            }
        }

    }
}
